/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package global

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
	"nodemessage.com/ruov-cli/consts"
	"nodemessage.com/ruov-cli/rlog"
	"nodemessage.com/ruov-cli/utils"
)

// InstallCmd represents the install command
var InstallCmd = &cobra.Command{
	Use:   "install",
	Short: "安装到环境变量",
	Long:  `会将ruov命令安装到环境变量中，使其在任何目录下都可用`,
	Run: func(cmd *cobra.Command, args []string) {
		installGlobal()
	},
}

// installGlobal 将程序添加到系统环境变量路径
func installGlobal() {
	// 获取当前可执行文件路径
	execPath, err := os.Executable()
	if err != nil {
		rlog.Logger.Fatal("获取可执行文件路径失败: %v", err)
		return
	}

	// 获取当前可执行文件的绝对路径和文件名
	absExecPath, err := filepath.Abs(execPath)
	if err != nil {
		rlog.Logger.Fatal("获取可执行文件绝对路径失败: %v", err)
		return
	}

	// 检查是否已经安装
	execName := filepath.Base(absExecPath)
	binDir := filepath.Join(consts.RootPath, "bin")
	targetPath := filepath.Join(binDir, execName)

	if _, err := os.Stat(targetPath); err == nil {
		rlog.Logger.Error("程序已经安装: %v", targetPath)
		rlog.Logger.Error("程序已安装，如需重新安装，请先运行 'ruov global uninstall' 命令")
		return
	}

	// 创建conf目录和setting.ini文件
	createConfFiles()

	// 根据操作系统类型执行不同的操作
	if runtime.GOOS == "windows" {
		installWindows(absExecPath)
	} else {
		installUnix(absExecPath)
	}
}

// createConfFiles 创建conf目录和setting.ini文件
func createConfFiles() {
	confDir := consts.ConfPath

	// 创建conf目录
	if _, err := os.Stat(confDir); os.IsNotExist(err) {
		err = os.MkdirAll(confDir, os.ModePerm)
		if err != nil {
			rlog.Logger.Error("创建conf目录失败: %v", err)
			rlog.Logger.Error("无法创建目录: %s", confDir)
			return
		}
		rlog.Logger.Info("已创建目录: %s", confDir)
	}

	// 使用工具函数初始化默认配置
	err := utils.InitDefaultConfig()
	if err != nil {
		rlog.Logger.Error("初始化默认配置失败: %v", err)
		rlog.Logger.Error("无法初始化配置文件: %v", err)
		return
	}

	// 成功初始化后不需要显示提示，因为InitDefaultConfig内部会处理
}

// installWindows 在Windows系统中将程序添加到PATH环境变量
func installWindows(absExecPath string) {
	// 使用已经在installGlobal中定义的变量
	execName := filepath.Base(absExecPath)
	binDir := filepath.Join(consts.RootPath, "bin")
	targetPath := filepath.Join(binDir, execName)

	// 确保bin目录存在
	if _, err := os.Stat(binDir); os.IsNotExist(err) {
		err = os.MkdirAll(binDir, os.ModePerm)
		if err != nil {
			rlog.Logger.Error("创建bin目录失败: %v", err)
			rlog.Logger.Error("无法创建目录: %s", binDir)
			return
		}
		rlog.Logger.Info("已创建目录: %s", binDir)
	}

	// 如果目标路径已存在，则先删除
	if _, err := os.Stat(targetPath); err == nil {
		err = os.Remove(targetPath)
		if err != nil {
			rlog.Logger.Error("删除现有文件失败: %v", err)
			rlog.Logger.Error("无法删除现有文件: %s", targetPath)
			return
		}
	}

	// 在Windows上创建符号链接需要管理员权限
	// 尝试创建符号链接
	cmdArgs := []string{"/c", "mklink", targetPath, absExecPath}
	cmd := exec.Command("cmd", cmdArgs...)
	err := cmd.Run()
	if err != nil {
		// 如果创建符号链接失败，则复制文件
		input, err := os.ReadFile(absExecPath)
		if err != nil {
			rlog.Logger.Error("读取源文件失败: %v", err)
			rlog.Logger.Error("无法读取源文件: %s", absExecPath)
			return
		}

		err = os.WriteFile(targetPath, input, 0755)
		if err != nil {
			rlog.Logger.Error("写入目标文件失败: %v", err)
			rlog.Logger.Error("无法写入目标文件: %s", targetPath)
			return
		}
		rlog.Logger.Warn("无法创建符号链接，已复制文件到目标位置")
	}

	// 先添加RUOV_HOME环境变量
	homeCmd := fmt.Sprintf(
		"[Environment]::SetEnvironmentVariable('RUOV_HOME', '%s', 'User')",
		consts.RootPath)
	cmd = exec.Command("powershell", "-Command", homeCmd)
	err = cmd.Run()
	if err != nil {
		rlog.Logger.Error("设置RUOV_HOME环境变量失败: %v", err)
		rlog.Logger.Warn("请手动将RUOV_HOME环境变量设置为: %s", consts.RootPath)
		return
	} else {
		rlog.Logger.Info("已设置RUOV_HOME环境变量为: %s", consts.RootPath)
	}

	// 使用%RUOV_HOME%添加到PATH环境变量
	pathCmd := fmt.Sprintf(
		"[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%%RUOV_HOME%%\\bin', 'User')")
	cmd = exec.Command("powershell", "-Command", pathCmd)
	err = cmd.Run()
	if err != nil {
		rlog.Logger.Error("添加到PATH环境变量失败: %v", err)
		rlog.Logger.Warn("请手动将 %RUOV_HOME%\\bin 添加到PATH环境变量")
	} else {
		rlog.Logger.Info("已将 %RUOV_HOME%\\bin 添加到PATH环境变量")
	}

	rlog.Logger.Info("已成功将 %s 安装到 %s", execName, binDir)
	rlog.Logger.Info("现在可以在任何目录使用 %s 命令", strings.TrimSuffix(execName, filepath.Ext(execName)))
	rlog.Logger.Warn("需要重新启动命令提示符或PowerShell才能使环境变量生效")
}

// installUnix 在Unix/Linux系统中将程序添加到PATH环境变量
func installUnix(absExecPath string) {
	// 在consts.RootPath目录下创建bin目录
	execName := filepath.Base(absExecPath)
	execNameWithoutExt := strings.TrimSuffix(execName, filepath.Ext(execName))
	binDir := filepath.Join(consts.RootPath, "bin")
	targetPath := filepath.Join(binDir, execNameWithoutExt)

	// 确保bin目录存在
	if _, err := os.Stat(binDir); os.IsNotExist(err) {
		err = os.MkdirAll(binDir, os.ModePerm)
		if err != nil {
			rlog.Logger.Error("创建bin目录失败: %v", err)
			rlog.Logger.Error("无法创建目录: %s", binDir)
			return
		}
		rlog.Logger.Info("已创建目录: %s", binDir)
	}

	// 创建符号链接
	if _, err := os.Stat(targetPath); err == nil {
		// 如果目标已存在，先移除
		err = os.Remove(targetPath)
		if err != nil {
			rlog.Logger.Error("删除现有链接失败: %v", err)
			rlog.Logger.Error("无法删除现有链接: %s", targetPath)
			return
		}
	}

	// 创建新的符号链接
	err := os.Symlink(absExecPath, targetPath)
	if err != nil {
		rlog.Logger.Error("创建符号链接失败: %v", err)
		rlog.Logger.Error("无法创建符号链接: %s -> %s", absExecPath, targetPath)
		return
	}

	// 确保可执行权限
	err = os.Chmod(absExecPath, 0755)
	if err != nil {
		rlog.Logger.Error("设置可执行权限失败: %v", err)
	}

	// 添加到PATH环境变量和RUOV_HOME
	homeDir, err := os.UserHomeDir()
	if err != nil {
		rlog.Logger.Error("获取用户主目录失败: %v", err)
		rlog.Logger.Warn("请手动将 $RUOV_HOME/bin 添加到PATH环境变量")
		rlog.Logger.Warn("请手动将RUOV_HOME环境变量设置为: %s", consts.RootPath)
		return
	}

	// 检查常见的shell配置文件
	shellFiles := []string{".bashrc", ".zshrc", ".profile"}
	shellFilePath := ""
	for _, file := range shellFiles {
		path := filepath.Join(homeDir, file)
		if _, err := os.Stat(path); err == nil {
			shellFilePath = path
			break
		}
	}

	if shellFilePath != "" {
		// 尝试添加到shell配置文件
		exportLines := fmt.Sprintf(
			"\n# ruov-cli 环境变量\nexport RUOV_HOME=\"%s\"\nexport PATH=\"$PATH:$RUOV_HOME/bin\"\n",
			consts.RootPath)

		appendFile, err := os.OpenFile(shellFilePath, os.O_APPEND|os.O_WRONLY, 0644)
		if err != nil {
			rlog.Logger.Error("无法打开shell配置文件: %v", err)
			rlog.Logger.Warn("请手动将以下行添加到你的shell配置文件中:")
			rlog.Logger.Warn("export RUOV_HOME=\"%s\"", consts.RootPath)
			rlog.Logger.Warn("export PATH=\"$PATH:$RUOV_HOME/bin\"")
		} else {
			defer appendFile.Close()
			if _, err := appendFile.WriteString(exportLines); err != nil {
				rlog.Logger.Error("无法写入shell配置文件: %v", err)
				rlog.Logger.Warn("请手动将以下行添加到你的shell配置文件中:")
				rlog.Logger.Warn("export RUOV_HOME=\"%s\"", consts.RootPath)
				rlog.Logger.Warn("export PATH=\"$PATH:$RUOV_HOME/bin\"")
			} else {
				rlog.Logger.Info("已将环境变量添加到: %s", shellFilePath)
				rlog.Logger.Info("- RUOV_HOME=%s", consts.RootPath)
				rlog.Logger.Info("- PATH增加: $RUOV_HOME/bin")
			}
		}
	} else {
		rlog.Logger.Warn("未找到shell配置文件，请手动添加以下环境变量:")
		rlog.Logger.Warn("export RUOV_HOME=\"%s\"", consts.RootPath)
		rlog.Logger.Warn("export PATH=\"$PATH:$RUOV_HOME/bin\"")
	}

	rlog.Logger.Info("已成功将 %s 链接到 %s", execName, targetPath)
	rlog.Logger.Info("现在可以在任何目录使用 %s 命令", execNameWithoutExt)
	if shellFilePath != "" {
		rlog.Logger.Warn("请执行 'source %s' 或重新打开终端以使环境变量生效", shellFilePath)
	}
}
